#include "server.h"

Server::Server(QHostAddress a, quint16 p, bool onlyReceive) : Connection(a,p,onlyReceive)
{
	map = new Map(-250,-250,500,500);
    pingTimer = new QTimer();
    pingTimer->setInterval(40);
    connect(pingTimer, SIGNAL(timeout()),this,SLOT(broadcastState()));
    //connect(map,SIGNAL(hitPlayer(Player*,Player*)), this, SLOT(onHitPlayer(Player*,Player*)));
    //connect(map,SIGNAL(hehe()), this, SLOT(hehe()));
    if (connect(map,SIGNAL(hitPlayer(Player*,Player*)), this, SLOT(onHitPlayer(Player*,Player*)))) qDebug() << "YEAH";
}

Server::Server(bool onlyReceive) : Connection(onlyReceive)
{
	map = new Map(-250,-250,500,500);
    pingTimer = new QTimer();
    pingTimer->setInterval(40);
    connect(pingTimer, SIGNAL(timeout()),this,SLOT(broadcastState()));
    if (connect(map,SIGNAL(hitPlayer(Player*,Player*)), this, SLOT(onHitPlayer(Player*,Player*)))) qDebug() << "YEAH";
    //connect(map,SIGNAL(hehe()), this, SLOT(hehe()));
}

void Server::hehe()
{
	qDebug() << "hehe";
}

void Server::startServer(quint16 port)
{
	connectionHash.clear();
    setPort(port);
    connToHost();
    pingTimer->start();
    connect(this, SIGNAL(newPacket(Packet*)),this, SLOT(onNewPacket(Packet*)));
}

void Server::stopServer()
{
    PacketData* toSend = new PacketData();
    toSend->appendString("DISCONNECT");
    sendToAll(toSend,false);

    disconnFromHost();
    pingTimer->stop();

    QHashIterator<QString,ServerConnection*> it(connectionHash);
    while (it.hasNext())
    {
        it.next();
        ServerConnection* conn = it.value();
        conn->flushSendQueue();
        conn->disconnFromHost();
    }
    //connectionHash.clear();
}

void Server::sendToAll(PacketData* data,bool reliable, bool queue, QVector<ServerConnection*> *except)
{
    QHashIterator<QString,ServerConnection*> it(connectionHash);
    int i = 1;
    while (it.hasNext())
    {
        it.next();
        ServerConnection* conn = it.value();
        if (except != NULL)
        {
            if (except->contains(conn))
            {
                continue;
            }
        }

        conn->sendPacket(new PacketData(data->getData()),reliable, queue);
    }
    delete data;
}

void Server::onNewPacket(Packet* packet)
{
    ServerConnection *conn;
    QString key = packet->getHostPortKey();

    if (connectionHash.contains(key))
    {
    	//delete conn;
        conn = connectionHash.value(key);
        conn->processPacket(packet);
    } else {
    	//qDebug()<< "new connection!" << key;
        conn = new ServerConnection(packet->getSenderAddress(), packet->getSenderPort(),false,this);
        connect(conn, SIGNAL(newPlayerConnected(ConnectionPlayer*)),this,SIGNAL(newPlayerConnected(ConnectionPlayer*)));
        connect(conn, SIGNAL(connectionStateChanged(QAbstractSocket::SocketState)),this, SLOT(onConnectionStateChanged(QAbstractSocket::SocketState)));
        connectionHash.insert(key, conn);

        conn->setPlayerId(connectionHash.count());

        Player* player = new Player(0,0);
        player->setConnectionPlayer(conn);
		player->setIsRemote(true);
		map->addPlayer(player, true);
		player->setIsAlive(false);
        conn->processPacket(packet);
    }
}

void Server::broadcastPing()
{
    PacketData* toSend = new PacketData();
    toSend->appendString("PING");
    toSend->appendInt(time(0));
    sendToAll(toSend, false);
}

void Server::broadcastState()
{
	map->spawnPlayers();

	PacketData* toSend = new PacketData();
	toSend->appendString("STATE");
	QHashIterator<QString,ServerConnection*> it(connectionHash);
	while (it.hasNext())
	{
		it.next();
		ServerConnection* conn = it.value();
		toSend->appendInt(conn->getPlayerId());
		toSend->appendInt(conn->getIsAlive());
		if (conn->getIsAlive()) {
			toSend->appendReal(conn->getPos().rx());
			toSend->appendReal(conn->getPos().ry());
			toSend->appendInt(conn->dirs.at(0));
			toSend->appendInt(conn->dirs.at(1));
			toSend->appendInt(conn->getAngle());
			toSend->appendInt(conn->getIsReloading());
		}
	}

	sendToAll(toSend, false, false);
}

void Server::onHitPlayer(Player* p1, Player* p2)
{
	qDebug() << "decrease hit player health ";
	p2->decreaseHealth(10);
}

void Server::onConnectionStateChanged(QAbstractSocket::SocketState st)
{
    switch (st)
    {
        case QAbstractSocket::UnconnectedState:
            ServerConnection* conn = static_cast<ServerConnection*>(sender());

            PacketData* toSend = new PacketData();
            toSend->appendString("QUIT");
            toSend->appendInt(conn->getPlayerId());
            QVector<ServerConnection*> *except = new QVector<ServerConnection*>();
            except->append(conn);
            sendToAll(toSend,true,except);

            emit playerDisconnected(conn);

            connectionHash.remove(conn->getHostPortKey());

            delete conn;
        break;
    }
}

QHash<QString, ServerConnection*> Server::getConnectionHash()
{
    return connectionHash;
}
